/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#ifndef __LIB3D_BASERANDOMINITIALIZER_H__
#define __LIB3D_BASERANDOMINITIALIZER_H__

#include <xml/Object.h>
#include <xml/Stream.h>
#include <xml/Saver.h>
#include <math/utl.h>
#include <stddef.h>
#include "../ParticleInitializer.h"

namespace liba
{
	namespace lib3d
	{
		namespace particles
		{
			template<typename DataType, int Offset>
			class BaseRandomInitializer : public ParticleInitializer
			{
			protected:
				DataType _base;
				DataType _randomMin;
				DataType _randomMax;
			protected:
				virtual ~BaseRandomInitializer()
				{
				}
			public:
				BaseRandomInitializer()
				{
					memset(&_base,      0, sizeof(DataType));
					memset(&_randomMin, 0, sizeof(DataType));
					memset(&_randomMax, 0, sizeof(DataType));
				}
				
				virtual void initialize_particle(Particle * particles)
				{
					*reinterpret_cast<DataType*>(reinterpret_cast<char*>(particles) + Offset) = _base + math::random(_randomMin, _randomMax);
				}
				
				void set_base(const DataType & base)
				{
					_base = base;
				}
				
				DataType get_base()
				{
					return _base;
				}
				
				void set_random(const DataType & randomMin, const DataType & randomMax)
				{
					_randomMin = randomMin;
					_randomMax = randomMax;
				}
				
				void get_random(DataType * randomMin, DataType * randomMax)
				{
					*randomMin = _randomMin;
					*randomMax = _randomMax;
				}

				virtual void on_save_attributes(xml::SaverBase * saver) const
				{
					DataType zeroValue;
					memset(&zeroValue, 0, sizeof(DataType));

					if(_base != zeroValue)
						saver->save_attribute("Base", _base);

					if(_randomMin != zeroValue)
						saver->save_attribute("RandomMin", _randomMin);

					if(_randomMax != zeroValue)
						saver->save_attribute("RandomMax", _randomMax);
				}
				
				virtual bool on_attribute(xml::Provider * provider, const std::string & name, const std::string & value)
				{
					// base origin
					if(name == "Base")
						return converter::convert(value, &_base);
					
					// random min border
					if(name == "RandomMin")
						return converter::convert(value, &_randomMin);
					
					// random max border
					if(name == "RandomMax")
						return converter::convert(value, &_randomMax);
					
					// unknown attribute
					return false;
				}
			};
			
			typedef BaseRandomInitializer<math::Vector3<Float>, offsetof(Particle, currentState.position)> OriginInitializer;
			typedef BaseRandomInitializer<Color,                offsetof(Particle, currentState.color)>    ColorInitializer;
			typedef BaseRandomInitializer<Float,                offsetof(Particle, currentState.angle)>    RotationInitializer;
			typedef BaseRandomInitializer<Float,                offsetof(Particle, currentState.alpha)>    AlphaInitializer;
		}
	}
}

#endif